API REFERENCE
=============

Complete public API for Lingenic-Text, organized by module.
All types and subprograms are listed with their contracts.


================================================================================
LINGENIC_TEXT (Root Package)
================================================================================

Types:

  subtype Codepoint is Natural range 0 .. 16#10_FFFF#;
    Full Unicode codespace (0 to 1,114,111).

  subtype Byte is Natural range 0 .. 255;
    Single byte value.

  type Byte_Array is array (Positive range <>) of Byte;
    Contiguous byte sequence.  Used for all UTF-8 data, buffers,
    and UCD file contents.

Constants:

  Max_Codepoint    : constant := 16#10_FFFF#;
  Codepoint_Count  : constant := 1_114_112;

  Surrogate_First  : constant := 16#D800#;
  Surrogate_Last   : constant := 16#DFFF#;

  LF, CR, Space, Tab, Hash, Dot, Semicolon : constant Byte;
  Zero, Nine, Upper_A, Upper_F             : constant Byte;

Functions:

  Is_Scalar_Value(CP) -> Boolean
    True if CP is not in the surrogate range (D800..DFFF).

  Is_Noncharacter(CP) -> Boolean
    True if CP is a Unicode noncharacter (FDD0..FDEF, xFFFE, xFFFF).

  Is_Hex_Digit(B) -> Boolean
  Hex_Value(B) -> Natural
  Is_Line_End(B) -> Boolean
  Is_Field_Space(B) -> Boolean
    Byte classification for UCD file parsing.


================================================================================
LINGENIC_TEXT.UTF8
================================================================================

  procedure Decode
    (Source : Byte_Array;
     Pos    : Positive;
     CP     : out Codepoint;
     Length : out Positive;
     Valid  : out Boolean);

    Pre:  Pos in Source'Range
          Source'Last < Positive'Last
    Post: Length in 1..4
          Valid = UTF8_Spec.Well_Formed_At(Source, Pos)
          if Valid: CP = Decoded_At, Is_Scalar_Value(CP),
                    Encoded_At(Source, Pos, CP), Length = Lead_Length
          if not Valid: CP = 0, Length = 1

  procedure Encode
    (CP     : Codepoint;
     Target : in out Byte_Array;
     Pos    : Positive;
     Length : out Positive);

    Pre:  Is_Scalar_Value(CP)
          Pos in Target'Range
          Target'Last < Positive'Last
          Target'Last - Pos >= Encoded_Length(CP) - 1
    Post: Length = Encoded_Length(CP)
          Encoded_At(Target, Pos, CP)
          Well_Formed_At(Target, Pos)
          Decoded_At(Target, Pos) = CP
          Frame: bytes outside [Pos..Pos+Length-1] unchanged


================================================================================
LINGENIC_TEXT.UCD_PARSER
================================================================================

Types:

  subtype Property_Index is Natural range 0 .. 255;
  type Property_Table is array (Codepoint) of Property_Index;
  type Value_Name is record First : Positive; Last : Natural; end record;
  type Value_Name_Array is array (1 .. 255) of Value_Name;

  procedure Parse_Property_File
    (Source     : Byte_Array;
     Names      : Value_Name_Array;
     Num_Values : Property_Index;
     Table      : out Property_Table;
     Success    : out Boolean);

    Post: for all CP => Table(CP) in 0..Num_Values
          for all CP => Table(CP) = Expected_Value(Source, 1, CP, ...)

  procedure Extract_Value_Names
    (Source     : Byte_Array;
     Names      : out Value_Name_Array;
     Num_Values : out Property_Index;
     Success    : out Boolean);


================================================================================
LINGENIC_TEXT.FILE_IO
================================================================================

  procedure Read_File
    (Name    : String;
     Buffer  : out Byte_Array;
     Length  : out Natural;
     Success : out Boolean);

    Maximum file size: 4 MB.  SPARK_Mode(Off).


================================================================================
LINGENIC_TEXT.PROPERTIES
================================================================================

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Post: if Success then Initialized

  function Initialized return Boolean;

  -- Script (UAX #24)
  function Get_Script(CP) -> Property_Index;
  function Script_Name_Count -> Property_Index;
  function Script_Name(Idx) -> String;

  -- Script_Extensions (UAX #24)
  function Is_In_Script_Extensions(CP, Script_Idx) -> Boolean;
  function Get_Script_Extension_Count(CP) -> Scx_Member_Count;
  function Get_Script_Extension(CP, K) -> Property_Index;

  -- Grapheme_Cluster_Break (UAX #29)
  function Get_GBP(CP) -> Property_Index;
  function GBP_Name_Count -> Property_Index;
  function GBP_Name(Idx) -> String;
  function GBP_To_Abstract(Idx) -> GBP_Value;

  -- Extended_Pictographic (UTS #51)
  function Get_ExtPict(CP) -> Boolean;

  -- Indic_Conjunct_Break (UAX #44)
  function Get_InCB(CP) -> Property_Index;
  function InCB_Name_Count -> Property_Index;
  function InCB_To_Abstract(Idx) -> InCB_Value;

  -- Word_Break (UAX #29)
  function Get_WBP(CP) -> Property_Index;
  function WBP_Name_Count -> Property_Index;
  function WBP_Name(Idx) -> String;
  function WBP_To_Abstract(Idx) -> WBP_Value;

  -- Sentence_Break (UAX #29)
  function Get_SBP(CP) -> Property_Index;
  function SBP_Name_Count -> Property_Index;
  function SBP_Name(Idx) -> String;
  function SBP_To_Abstract(Idx) -> SBP_Value;

  -- East_Asian_Width (UAX #11)
  function Get_EAW(CP) -> Property_Index;
  function EAW_Name_Count -> Property_Index;
  function EAW_Name(Idx) -> String;
  function EAW_To_Abstract(Idx) -> EAW_Value;

  -- Line_Break (UAX #14)
  function Get_LBP(CP) -> LBP_Value;
    Returns resolved class (after LB1, QU/OP/CP splits).

  -- General_Category (UAX #44)
  function Get_GC(CP) -> Property_Index;
  function GC_Name_Count -> Property_Index;
  function GC_Name(Idx) -> String;

  -- Bidi_Class (UAX #9)
  function Get_BC(CP) -> BC_Value;
    Returns resolved class.

  -- Joining_Type (UAX #44)
  function Get_JT(CP) -> JT_Value;

  -- Bidi_Mirrored (UAX #9)
  function Get_Bidi_Mirrored(CP) -> Boolean;

  -- XID_Start / XID_Continue (UAX #31)
  function Get_XID_Start(CP) -> Boolean;
  function Get_XID_Continue(CP) -> Boolean;

  All accessors: Pre => Initialized.


================================================================================
LINGENIC_TEXT.GRAPHEMES
================================================================================

  procedure Next_Grapheme_Cluster_Break
    (Text     : Byte_Array;
     Pos      : Positive;
     Next_Pos : out Positive);

    Pre:  Text'First = 1, Text'Last >= 1, Text'Last < Positive'Last
          Pos in Text'Range, Properties.Initialized
    Post: Next_Pos = Next_GCB_From(Text, Pos)
          Next_Pos > Pos
          Next_Pos <= Text'Last + 1


================================================================================
LINGENIC_TEXT.WORDS
================================================================================

  procedure Next_Word_Break
    (Text     : Byte_Array;
     Pos      : Positive;
     Next_Pos : out Positive);

    Pre:  Text'First = 1, Text'Last >= 1, Text'Last < Positive'Last
          Pos in Text'Range, Properties.Initialized
    Post: Next_Pos = Next_WB_From(Text, Pos)
          Next_Pos > Pos
          Next_Pos <= Text'Last + 1


================================================================================
LINGENIC_TEXT.SENTENCES
================================================================================

  procedure Next_Sentence_Break
    (Text     : Byte_Array;
     Pos      : Positive;
     Next_Pos : out Positive);

    Pre:  Text'First = 1, Text'Last >= 1, Text'Last < Positive'Last
          Pos in Text'Range, Properties.Initialized
    Post: Next_Pos = Next_SB_From(Text, Pos)
          Next_Pos > Pos
          Next_Pos <= Text'Last + 1


================================================================================
LINGENIC_TEXT.LINE_BREAK
================================================================================

  procedure Next_Line_Break
    (Text     : Byte_Array;
     Pos      : Positive;
     Next_Pos : out Positive);

    Pre:  Text'First = 1, Text'Last >= 1, Text'Last < Positive'Last
          Pos in Text'Range, Properties.Initialized
    Post: Next_Pos = Next_LB_From(Text, Pos)
          Next_Pos > Pos
          Next_Pos <= Text'Last + 1


================================================================================
LINGENIC_TEXT.NORMALIZATION
================================================================================

Types:

  type Norm_Status is (Success, Buffer_Overflow, Invalid_Input);
  type Normalization_Form is (NFD, NFC, NFKD, NFKC);
  type QC_Value is (QC_Yes, QC_No, QC_Maybe);

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Post: if Success then Initialized and Data_All_Terminal

  function Initialized return Boolean;
  function Data_All_Terminal return Boolean;  -- Ghost

  procedure Normalize
    (Input  : Byte_Array;
     Form   : Normalization_Form;
     Output : in out Byte_Array;
     Last   : out Natural;
     Status : out Norm_Status);

    Pre:  Initialized, Data_All_Terminal
          Input'Length >= 1, Output'Length >= 1
          Output'Length <= Max_Norm_Acc
    Post: if Success then
            Last in Output'First..Output'Last
            NFD/NFKD: Ghost_Is_NFD(Output, Output'First, Last)
            NFC/NFKC: Ghost_Is_NFC(Output, Output'First, Last, ...)
          else Last = Output'First - 1

  function Quick_Check(Input, Form) -> QC_Value;
    Pre: Initialized, Input'Length >= 1

  function Is_Normalized(Input, Form) -> Boolean;
    Pre: Initialized, Input'Length >= 1

  function Get_CCC(CP) -> CCC_Value;
  function Get_NFC_QC(CP) -> QC_Value;
  function Get_NFKC_QC(CP) -> QC_Value;
    Pre: Initialized


================================================================================
LINGENIC_TEXT.CASE_MAPPING
================================================================================

Types:

  type Case_Status is (Success, Buffer_Overflow, Invalid_Input);

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Pre: Properties.Initialized
    Post: if Success then Initialized

  function Initialized return Boolean;

  procedure Uppercase(Input, Output, Last, Status);
    Pre:  Initialized, Input/Output valid
    Post: if Success then Last - Output'First + 1 = Ghost_Upper_Total(Input)

  procedure Lowercase(Input, Output, Last, Status);
    Post: if Success then Last - Output'First + 1 = Ghost_Lower_Total(Input)

  procedure Titlecase(Input, Output, Last, Status);
    Pre:  additionally Input'First = 1, Properties.Initialized
    Post: if Success then Last - Output'First + 1 = Ghost_Title_Total(Input)

  procedure Casefold(Input, Output, Last, Status);
    Post: if Success then Last - Output'First + 1 = Ghost_Fold_Total(Input)

  function Is_Cased(CP) -> Boolean;
  function Is_Case_Ignorable(CP) -> Boolean;

  function Get_Upper_Map_Len(CP) -> Natural;
  function Get_Upper_Map_CP(CP, Idx) -> Codepoint;
  function Get_Lower_Map_Len(CP) -> Natural;
  function Get_Lower_Map_CP(CP, Idx) -> Codepoint;
  function Get_Title_Map_Len(CP) -> Natural;
  function Get_Title_Map_CP(CP, Idx) -> Codepoint;
  function Get_Fold_Map_Len(CP) -> Natural;
  function Get_Fold_Map_CP(CP, Idx) -> Codepoint;
    Pre: Initialized (+ Idx bounds for *_Map_CP)


================================================================================
LINGENIC_TEXT.COLLATION
================================================================================

Types:

  type Variable_Weight_Option is (Non_Ignorable, Shifted);
  type Comparison_Result is (Less, Equal, Greater);

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Pre: Normalization.Initialized
    Post: if Success then Initialized

  function Initialized return Boolean;

  procedure Compare
    (Left, Right : Byte_Array;
     Option      : Variable_Weight_Option;
     Result      : out Comparison_Result;
     Success     : out Boolean);

    Pre: Initialized, Normalization.Initialized,
         Normalization.Data_All_Terminal

  procedure Sort_Key
    (Input   : Byte_Array;
     Option  : Variable_Weight_Option;
     Key     : in out Byte_Array;
     Last    : out Natural;
     Success : out Boolean);

    Post: if Success then Last in Key'First..Key'Last
          else Last = Key'First - 1


================================================================================
LINGENIC_TEXT.BIDI
================================================================================

Types:

  subtype Embedding_Level is Natural range 0 .. 126;
  subtype Paragraph_Length is Natural range 0 .. Max_Paragraph_CPs;
  type Level_Array is array (1 .. Max_Paragraph_CPs) of Embedding_Level;
  type Index_Array is array (1 .. Max_Paragraph_CPs) of Natural;
  type Paragraph_Direction is (Dir_Auto, Dir_LTR, Dir_RTL);

Constants:

  Max_Depth          = 125
  Max_Paragraph_CPs  = 4096

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Pre: Properties.Initialized
    Post: if Success then Initialized

  function Initialized return Boolean;

  procedure Resolve_Levels
    (Text       : Byte_Array;
     Dir        : Paragraph_Direction;
     Levels     : out Level_Array;
     Num_CPs    : out Paragraph_Length;
     Para_Level : out Embedding_Level;
     Success    : out Boolean);

    Post: if Success then
            Num_CPs >= 1, Para_Level <= 1
            for all I in 1..Num_CPs => Levels(I) <= Max_Depth + 1
          else Num_CPs = 0

  procedure Reorder
    (Levels     : Level_Array;
     Num_CPs    : Paragraph_Length;
     Para_Level : Embedding_Level;
     Order      : out Index_Array;
     Success    : out Boolean);

    Post: if Success then
            for all I => Order(I) in 1..Num_CPs           (range)
            for all V => (for some I => Order(I) = V)      (surjection)

  function Needs_Mirror(CP, Level) -> Boolean;
    Post: Result = (Level mod 2 = 1) and then Get_Bidi_Mirrored(CP)


================================================================================
LINGENIC_TEXT.EMOJI
================================================================================

Types:

  type Emoji_Sequence_Type is
    (Not_Emoji, Emoji_Character, Emoji_Presentation_Seq,
     Emoji_Keycap_Seq, Emoji_Modifier_Seq, Emoji_Flag_Seq,
     Emoji_Tag_Seq, Emoji_ZWJ_Seq);

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Post: if Success then Initialized

  function Initialized return Boolean;

  function Is_Emoji(CP) -> Boolean;
  function Is_Emoji_Presentation(CP) -> Boolean;
  function Is_Emoji_Modifier(CP) -> Boolean;
  function Is_Emoji_Modifier_Base(CP) -> Boolean;
  function Is_Emoji_Component(CP) -> Boolean;
    Pre: Initialized

  function Classify_Sequence(Input : Byte_Array) -> Emoji_Sequence_Type;
    Pre:  Initialized, Input'Length in 1..Max_Sequence_Bytes
    Post: Result = Ghost_Classify_All(Input)


================================================================================
LINGENIC_TEXT.EAW
================================================================================

  function Display_Width(CP : Codepoint) return Natural;
    Pre:  Properties.Initialized
    Post: Result = Cell_Width(EAW_To_Abstract(Get_EAW(CP)))
          Wide/Fullwidth -> 2, others -> 1


================================================================================
LINGENIC_TEXT.IDENTIFIERS
================================================================================

  function Is_Identifier_Start(CP : Codepoint) return Boolean;
    Pre:  Properties.Initialized
    Post: Result = Properties.Get_XID_Start(CP)

  function Is_Identifier_Part(CP : Codepoint) return Boolean;
    Pre:  Properties.Initialized
    Post: Result = Properties.Get_XID_Continue(CP)


================================================================================
LINGENIC_TEXT.IDNA
================================================================================

Types:

  type IDNA_Result is
    (Success, Invalid_Input, Disallowed_Codepoint, Label_Too_Long,
     Domain_Too_Long, Invalid_Hyphen, Leading_Combining_Mark,
     NFC_Failure, Bidi_Failure, ContextJ_Failure, Punycode_Failure,
     Buffer_Overflow, STD3_Failure, Too_Many_Labels, Empty_Label);

  type IDNA_Options is record
    Check_Hyphens     : Boolean;
    Check_Bidi        : Boolean;
    Check_Joiners     : Boolean;
    Use_STD3_Rules    : Boolean;
    Verify_DNS_Length  : Boolean;
  end record;

  procedure Initialize(UCD_Dir : String; Success : out Boolean);
    Post: if Success then Initialized

  function Initialized return Boolean;

  procedure To_ASCII
    (Input : Byte_Array; Options : IDNA_Options;
     Output : in out Byte_Array; Last : out Natural;
     Status : out IDNA_Result);

    Pre:  Initialized, Properties.Initialized,
          Normalization.Initialized, Normalization.Data_All_Terminal
    Post: if Success then
            Last in Output'First..Output'Last
            for all I in Output'First..Last => Output(I) < 128
            if Verify_DNS_Length then length in 1..253
          else Last = Output'First - 1

  procedure To_Unicode
    (Input : Byte_Array; Options : IDNA_Options;
     Output : in out Byte_Array; Last : out Natural;
     Status : out IDNA_Result);

    Post: if Success then Last in Output'First..Output'Last
          else Last = Output'First - 1


================================================================================
LINGENIC_TEXT.TEXT_TRANSFORM (Generic)
================================================================================

  generic
    type State_Type is private;
    with function Output_Valid(S, Output, Last) -> Boolean;
    with function Partial_Valid(S, Output, Pos) -> Boolean;
    with procedure On_Codepoint(State, CP, Output, Pos, OK)
      Pre:  Partial_Valid(State, Output, Pos) and OK
      Post: Pos >= Pos'Old, Pos <= Output'Last + 1,
            if OK then Partial_Valid(State, Output, Pos);
    with procedure On_Finish(State, Output, Pos, OK)
      Pre:  Partial_Valid(State, Output, Pos) and OK
      Post: Pos >= Pos'Old, Pos <= Output'Last + 1,
            if OK and Pos > Output'First then
              Output_Valid(State, Output, Pos - 1);
  procedure Lingenic_Text.Text_Transform
    (Input  : Byte_Array;
     State  : in out State_Type;
     Output : in out Byte_Array;
     Last   : out Natural;
     OK     : out Boolean);

    Pre:  Input'Length >= 1, Output'Length >= 1
          Partial_Valid(State, Output, Output'First)
    Post: if OK then
            Last in Output'First..Output'Last
            Output_Valid(State, Output, Last)
          else Last = Output'First - 1


================================================================================
INITIALIZATION ORDER SUMMARY
================================================================================

  Required initialization order:

    1. Properties.Initialize(UCD_Dir, ...)
    2. Emoji.Initialize(UCD_Dir, ...)         -- independent of Properties
    3. Normalization.Initialize(UCD_Dir, ...)  -- no dependencies
    4. Case_Mapping.Initialize(UCD_Dir, ...)   -- requires Properties
    5. Collation.Initialize(UCD_Dir, ...)      -- requires Normalization
    6. Bidi.Initialize(UCD_Dir, ...)           -- requires Properties
    7. IDNA.Initialize(UCD_Dir, ...)           -- requires Properties + Normalization

  Modules without Initialize:
    Graphemes, Words, Sentences, Line_Break  -- require Properties.Initialized
    EAW, Identifiers                          -- require Properties.Initialized
